using System;
using Introspector = Velocity4Net.Util.Introspection.Introspector;
using MethodInvocationException = Velocity4Net.Errors.MethodInvocationException;
using InternalContextAdapter = Velocity4Net.Ctx.InternalContextAdapter;
using Velocity4Net.Errors;
using Velocity4Net.Runtime.Logging;

namespace Velocity4Net.Runtime.Parse.AST
{

    /**
     * Executor that simply tries to execute a get(key)
     * operation. This will try to find a get(key) method
     * for any type of object, not just objects that
     * implement the Map interface as was previously
     * the case.
     *
     * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
     * @version $Id: GetExecutor.java 687177 2008-08-19 22:00:32Z nbubna $
     */
    public class GetExecutor : AbstractExecutor
    {
        private Introspector introspector;

        // This is still threadsafe because this object is only read except in the C'tor.
        private Object[] _params = { };

        /**
         * @param log
         * @param introspector
         * @param clazz
         * @param property
         * @since 1.5
         */
        public GetExecutor(Log log, Introspector introspector,
                 Type clazz, String property)
        {
            this.log = log;
            this.introspector = introspector;

            // If you passed in null as property, we don't use the value
            // for parameter lookup. Instead we just look for get() without
            // any parameters.
            //
            // In any other case, the following condition will set up an array
            // for looking up get(String) on the class.

            if (property != null)
            {
                this._params = new Object[] { property };
            }
            discover(clazz);
        }


        /**
         * @since 1.5
         */
        protected void discover(Type clazz)
        {
            try
            {
                setMethod(introspector.getMethod(clazz, "get_", _params));
            }
            /**
             * pass through application level runtime exceptions
             */
            catch (ApplicationException e)
            {
                throw e;
            }
            catch (System.Exception e)
            {
                String msg = "Exception while looking for get('" + _params[0] + "') method";
                log.error(msg, e);
                throw new VelocityException(msg, e);
            }
        }

        /**
         * @see org.apache.velocity.runtime.parser.node.AbstractExecutor#execute(java.lang.Object)
         */
        public override Object Execute(Object o)
        {
            return isAlive() ? getMethod().Invoke(o, _params) : null;
        }
    }
}
